Chanquo2系


概要

Chanquo = Typeを接続用パラメータとして扱うGoのchannelもどき for Unity。


1系は正直適当な実装だったんで、goのコードを読みながらアップグレードを目論む。

互換性は破壊されちゃったらごめんねみたいな想定。->破壊されました。やったぜ!


1系のダメなところ

・structを使えない(致命傷)

・マルチレシーブが特に必要ない感じ(タイムアウトとかがつけば別だが、それはそれで変な実装になる。

・yield returnしたい(一件受けたら云々とか)

・スロットルの概念があってもいい(N個をまとめて受ける)

・MainThreadDispatcher頼み(シーンを超えられるが、超えていいケースは少なかった。)

・コードが汚い(美しくない、拡張性が低い)

・Jobまわりを綺麗にアレしたいができない


ということで、2系の開発に取り組み、完成した。

Chanquo

https://github.com/sassembla/Chanquo



対応し途中のもの

・スロットルの概念があってもいい(N個をまとめて受ける)

・Jobまわりを綺麗にアレしたいができない


これらは途中。で、これら以外は対応できた。



結果

こんな感じの書き方ができるようになった。

var ch = Chan<T>.Make();

ch.Send(new T(){});


struct型Tを指定して、chの生成、chへとデータの送付。

goでの ch <- データ みたいな形。



受け取り側は複数パターンが使えて、


// start receiving data asynchronously.

ch.Receive(

    (T data, bool ok) => {

        // ok will become false when the channel is closed somewhere.

        // when ok is false, data is empty.

    }

);


1. select 文に対するcase data, ok := <- chのような扱い。

非同期で継続的な受け取り。これはv1と同じようなシグニチャになっている。と思ったけどそうでもないか。

誰かがchをCloseするとokがfalseな状態で飛んでくる。



// receive data until Chan<T> is closed.

yield return Channels.For<T>(

    T t =>

    {

        

    }

);


2. こちらはfor文での for data := range ch 相当。

Unityの場合はブロックせずに一定の位置で待つ、というのがasync汚染なしでは辛い(なんかいい手段ある?)という感じなので、

yield return と組み合わせる形にしている。



// wait first data then go through.

yield return Channels.WaitFirst<T>();


3. こちらは単純に <- ch と同じようなもの。

T型のデータがどこかから送信されると、yieldを抜ける。


goの場合はgoroutineでブロックをつくりまくっても全体には影響が及ばないのだが、

Unity C#の場合はブロックするとてきめんに詰む。


そのため、「その位置で待つ」という機能としてyield returnを使っている。


感想

より捨てやすく、なんとなーくUnityフレンドリーな書き方もできるようになった。

structが使えるのもよい。